#include "../Base.h"

typedef struct _WORKITEMFREEMEMORYINFO
{
	WORK_QUEUE_ITEM workItem;
	HANDLE pid;
	ULONG64 IsExecuteAddr;
	ULONG64 freeSize;
}WORKITEMFREEMEMORYINFO,*PWORKITEMFREEMEMORYINFO;


VOID
FreeMemoryWorkItem(
	_In_ PVOID Parameter
) {
	PWORKITEMFREEMEMORYINFO workInfo  =  (PWORKITEMFREEMEMORYINFO)Parameter;


	PEPROCESS process;
	NTSTATUS status = PsLookupProcessByProcessId(workInfo->pid, &process);
	if (!NT_SUCCESS(status)) {
		return ;
	}
	if (PsGetProcessExitStatus(process) != 0x103)
	{
		ObDereferenceObject(process);
		return ;
	}

	SIZE_T retSize = 0;
	ULONG64 exeValue = 0;
	BOOLEAN isSuccess = 0;

	int count = 0;
	while (1) {
		if (count > 10000) break;
		status = MmCopyVirtualMemory(process, (PVOID)workInfo->IsExecuteAddr,
			IoGetCurrentProcess(), &exeValue,sizeof(exeValue),KernelMode, &retSize);
		if (NT_SUCCESS(status) && exeValue == 1) {
			isSuccess = TRUE;
			break;
		}

		KernelSleep(10, FALSE);
		count++;
	}

	KAPC_STATE apc_state = { 0 };
	KeStackAttachProcess(process, &apc_state);
	if (isSuccess)
	{
		PVOID baseAddress = (PUCHAR)(workInfo->IsExecuteAddr - 0x500);
		ZwFreeVirtualMemory(NtCurrentProcess(), &baseAddress, &workInfo->freeSize, MEM_RELEASE);
	}

	KeUnstackDetachProcess(&apc_state);

	ExFreePoolWithTag(workInfo, 'yang');

	ObDereferenceObject(process);
	return;
}

NTSTATUS RemoteCall(HANDLE pid, PVOID shellCode, SIZE_T shellcodeSize) {
	PEPROCESS process;

	NTSTATUS status = PsLookupProcessByProcessId(pid, &process);
	if (!NT_SUCCESS(status)) {
		return STATUS_UNSUCCESSFUL;
	}
	if (PsGetProcessExitStatus(process) != 0x103)
	{
		ObDereferenceObject(process);
		return STATUS_UNSUCCESSFUL;
	}

	PETHREAD mainThread = NtGetProcessMainThread(process);
	PVOID wow64 = PsGetProcessWow64Process(process);
	BOOLEAN isWow64 = wow64 ? TRUE : FALSE;

	ObDereferenceObject(process);
	if (!mainThread) {
		return STATUS_UNSUCCESSFUL;
	}


	PUCHAR copyShellcode   = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, shellcodeSize, 'yang');
	memcpy(copyShellcode, shellCode, shellcodeSize);
	KAPC_STATE apc_state = { 0 };
	KeStackAttachProcess(process, &apc_state);
	status = PsSuspendThread(mainThread, NULL);
	do {

		PVOID baseAddr = NULL;
		SIZE_T size = shellcodeSize + PAGE_SIZE;
		status = ZwAllocateVirtualMemory(NtCurrentProcess(), &baseAddr, 0, &size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
		if (!NT_SUCCESS(status)) {
			break;
		}
		memset(baseAddr, 0, size);

		PUCHAR shellCodeAddr = (PUCHAR)baseAddr + PAGE_SIZE;

		memcpy(shellCodeAddr, copyShellcode,shellcodeSize);

		
	
		
		if (NT_SUCCESS(status)) {


			if (isWow64) {
				//x86进程


				/*
					 pushad               
					 mov eax,BC614E      
					 sub esp,28          
					 call eax            
					 add esp,28          
					 popad               
					 jmp dword ptr ds:[0]
				*/
				char bufCode[] = {
					0x60, 
					0xB8, 0x4E, 0x61, 0xBC, 0x00, 
					0x83, 0xEC, 0x28, 
					0xFF, 0xD0, 
					0x83, 0xC4, 0x28,
					0xB8, 0x78, 0x56, 0x34, 0x12, 
					0xC7, 0x00, 0x01, 0x00, 0x00, 0x00, 
					0x61, 
					0xFF, 0x25, 0x00, 0x00, 0x00, 0x00
				};


				PUCHAR teb64 = (PUCHAR)PsGetThreadTeb(mainThread);
				PUCHAR wowContext = (PUCHAR) * (PULONG64)(teb64 + 0x1488);

				*(PULONG)&bufCode[2] = (ULONG)shellCodeAddr;
				*(PULONG)&bufCode[15] = (ULONG)baseAddr + 0x500;
				*(PULONG)&bufCode[28] = (ULONG)(*(PULONG)(wowContext + 0xb8 + 0x4));
				memcpy(baseAddr, bufCode, sizeof(bufCode));


				//修改EIP
				*(PULONG)(wowContext + 0xb8 + 0x4) = (ULONG)baseAddr;

			
			}
			else {
				//x64进程  

				/*
						                     
						push r10                        
						push r11                        
						push r12                        
						push r13                        
						push r14                        
						push r15                        
						mov rax,121212121               
						sub rsp,A8                      
						call rax                        
						add rsp,A8                      
						pop r15                         
						pop r14                         
						pop r13                         
						pop r12                         
						pop r11                         
						pop r10                         
						pop r9                          
						pop r8                          
						pop rdi                         
						pop rsi                         
						pop rbp                         
						pop rbx                         
						pop rdx                         
						pop rcx                         
						mov rax,123456789               
						mov qword ptr ds:[rax],1        
						pop rax                         
						jmp qword ptr ds:[7FFC85682B7F] 
						add byte ptr ds:[rax],al        
						add byte ptr ds:[rax],al        
						add byte ptr ds:[rax],al        
						add byte ptr ds:[rax],al        
				
				*/


				char bufCode[] = {
					0x50,
					0x51,
					0x52,
					0x53,
					0x55,
					0x56,
					0x57,
					0x41,0x50,
					0x41,0x51,
					0x41,0x52,
					0x41,0x53,
					0x41,0x54,
					0x41,0x55,
					0x41,0x56,
					0x41,0x57,
					0x48,0xB8,0x21,0x21,0x21,0x21,0x01,0x00,0x00,0x00,
					0x48,0x81,0xEC,0xA0,0x00,0x00,0x00,
					0xFF,0xD0,
					0x48,0x81,0xC4,0xA0,0x00,0x00,0x00,
					0x41,0x5F,
					0x41,0x5E,
					0x41,0x5D,
					0x41,0x5C,
					0x41,0x5B,
					0x41,0x5A,
					0x41,0x59,
					0x41,0x58,
					0x5F,
					0x5E,
					0x5D,
					0x5B,
					0x5A,
					0x59,
					0x48,0xB8,0x89,0x67,0x45,0x23,0x01,0x00,0x00,0x00,
					0x48,0xC7,0x00,0x01,0x00,0x00,0x00,0x58,
					0xFF,0x25,0x00,0x00,0x00,0x00,
					0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
				};


				*(PULONG64)&bufCode[25] = (ULONG64)shellCodeAddr;
				*(PULONG64)&bufCode[73] = (ULONG64)baseAddr + 0x500;
				*(PULONG64)&bufCode[95] = (ULONG64)((PKTHREAD_WIN1803)mainThread)->TrapFrame->Rip;
				memcpy(baseAddr, bufCode, sizeof(bufCode));
				((PKTHREAD_WIN1803)mainThread)->TrapFrame->Rip = (ULONG64)baseAddr;


				
			}

			PWORKITEMFREEMEMORYINFO workInfo = (PWORKITEMFREEMEMORYINFO)ExAllocatePoolWithTag(NonPagedPool, sizeof(WORKITEMFREEMEMORYINFO), 'yang');

			workInfo->IsExecuteAddr = (ULONG64)baseAddr + 0x500;

			workInfo->pid = pid;

			workInfo->freeSize = size;

			ExInitializeWorkItem(&workInfo->workItem, FreeMemoryWorkItem, workInfo);

			ExQueueWorkItem(&workInfo->workItem, DelayedWorkQueue);
			status = PsResumeThread(mainThread, NULL);
		}


	} while (0);
	


	KeUnstackDetachProcess(&apc_state);
	ExFreePoolWithTag(copyShellcode, 'yang');
	return	status;

}